import { UiFrameworkExtension, ImplementedBy } from '../../components'
import { Link, Warning } from '@brillout/docpress'

Kind: cumulative.  
Environment: server.

<ImplementedBy noCustomGuide />

The `+Head` setting allows you to add `<head>` tags to your pages.

> See <Link href="/head-tags" /> for a general introduction and for other ways to add `<head>` tags.

> As explained <Link href="#only-html">below</Link>, it's only used when rendering the HTML of the first page the user visits. Consequently, it usually cannot be used for setting the `<title>` tag.

```jsx
// /pages/+Head.jsx
// /pages/+Head.vue
// Environment: server

import previewImage from './previewImage.jpg'
import favicon from './favicon.png'
import iconMobile from './iconMobile.png'

export function Head() {
  return <>
    {/* Adding a script tag */}
    <script type="text/javascript" src="https://example.com/some-script.js"></script>

    {/* Icon shown in the browser tab (aka favicon) */
    <link rel="icon" href={favicon}>

    {/* Icon shown on mobile homescreens (PWA) */
    <link rel="apple-touch-icon" href={iconMobile}>

    {/* Image shown when sharing on social sites (Twitter, WhatsApp, ...) */}
    <meta property="og:image" content={previewImage}>
  </>
}
```

## Using data

You can set `<head>` tags based on <Link href="/data-fetching">fetched data</Link> (or <Link href="/pageContext">`pageContext`</Link>) by using:

- <Link href="#head-inside-components">`<Head>` inside components</Link>
- <Link href="#useconfig-inside-data">`useConfig()` inside `+data`</Link>
- <Link href="#usedata-usepagecontext-inside-head">`useData()`/`usePageContext()` inside `+Head`</Link>

### `<Head>` inside components

You can use the <Link href="/Head">`<Head>` component</Link> inside your components:

```jsx
// Product.jsx

import { Head } from 'vike-react/Head' // or vike-{vue,solid}

function Product({ data }) {
  return <>
    <Head>
      {/* Image shown when sharing on social sites (Twitter, WhatsApp, ...) */}
      <meta property="og:image" content={data.product.image}>
    </Head>
    <h1>{data.product.name}</h1>
    <p>{data.product.description}</p>
  </>
}
```
> Here `data` comes from the props passed from the parent component, but it can also come from a data-fetching component hook such as [`const { data } = useSuspenseQuery()`](https://github.com/vikejs/vike-react/tree/main/packages/vike-react-query#head-tags) when using [`vike-react-query`](https://github.com/vikejs/vike-react/tree/main/packages/vike-react-query#readme).

> It also works inside `.vue` files (when using <Link href="/vike-vue">`vike-vue`</Link>).


### `useConfig()` inside `+data`

You can use the <Link href="/useConfig">`useConfig()` universal hook</Link> inside your <Link href="/data">`+data` hook</Link>.

```jsx
// pages/product/@id/+data.jsx

import { useConfig } from 'vike-react/useConfig' // or vike-{vue,solid}

export async function data() {
  const config = useConfig()
  const data = await fetchSomeData()
  config({
    Head: <>
      {/* Image shown when sharing on social sites (Twitter, WhatsApp, ...) */}
      <meta property="og:image" content={data.product.image}>
    </>
  })
}
```
> For Vue you can use the following:
> ```js
> import { h } from 'vue'
> config({
>   Head: h('meta', {
>     property: 'og:image',
>     content: data.product.image
>   })
> })
> ```

### `useData()`/`usePageContext()` inside `+Head`

The value defined by `+Head` is a component and thus you can use <Link href="/useData">`useData()`</Link> and <Link href="/usePageContext">`usePageContext()`</Link> as usual:

```jsx
// pages/product/@id/+Head.js

import { useData } from 'vike-react/useData' // or vike-{vue,solid}

export function Head() {
  const data = useData()
  return <>
    {/* Image shown when sharing on social sites (Twitter, WhatsApp, ...) */}
    <meta property="og:image" content={data.product.image}>
  </>
}
```


## Only HTML

### Only renders for the first page's HTML

The `<Head>` component is only used when rendering the HTML of the first page the user visits: the tags set by `<Head>` aren't updated upon <Link href="/client-routing">client-side page navigation</Link>.

### Limitation

The most notable limitation is that the `+Head` setting cannot be used to set the `<title>` value, because the title isn't updated when navigating to a page with a different title.

> See <Link href="#example">example below</Link> for a more detailed explanation.

Instead use the <Link href="/title">`+title`</Link> setting.

> For use cases where the `+Head` setting cannot be used, Vike offers tailored settings that update upon client-side navigation.


### A small limitation

This may seem like a major limitation but it actually isn't: you can use the `+Head` setting for the vast majority of use cases.

You can use `+Head` for setting `<head>` tags are read by HTML crawlers:

- Tags for social sites (Twitter, Instagram, ...) such as `<meta property="og:image">` (the preview image upon URL sharing).
  > Social site bots navigate your website only by using HTML requests: they don't execute client-side JavaScript and don't do client-side navigation.
- Tags for SEO such as `<meta name="description">`.
  > While Google can do client-side navigation, it still discovers `<head>` tags by using its HTML crawler.

You can use `+Head` for setting `<head>` tags that are global (they have the same value for all pages):

- Favicon.
  > Assuming all your pages share the same favicon (`<link rel="icon">`), there isn't any need to update the favicon upon client-side navigation.
- PWA settings.
  > PWA settings are global and there isn't any need to update them upon client-side navigation.
- `<script>`
  > Assuming the script applies to all your pages.

### Example

The following example showcases that using `+Head` for setting `<title>` doesn't work, while it does work for setting `<meta name="description">`.

```js
// /pages/index/+Head.jsx
// Environment: server

function Head() {
  return <>
    <title>AwesomeRockets</title>
    <meta name="description" content="The rocket company.">
  </>
}
```
```js
// /pages/about/+Head.jsx
// Environment: server

function Head() {
  return <>
    <title>About us</title>
    <meta name="description" content="We deliver payload to space.">
  </>
}
```

If the first URL the user visits is `/` then the rendered HTML is:

```html
<!DOCTYPE html>
<html>
  <head>
    <title>AwesomeRockets</title>
    <meta name="description" content="The rocket company.">
  </head>
</html>
```

If the user then clicks on a link `<a href="/about">About us</a>`, then Vike does client-side navigation and the page's title isn't updated: the browser sill shows `Welcome` even though the URL is now `/about`. That's because the <Link href="/client-routing">HTML isn't used upon client-side navigation (DOM manipulations are made instead)</Link> while `+Head` is only used when generating HTML.

> The `<Head>` component is only loaded on the server-side and only used when rendering HTML of the first page by design.

This isn't an issue for `<meta name="description">` tag because it's meant for search engines bots which
<Link href="#:~:text=Search%20engine%20bots%20as%20well%20as%20social%20sharing%20bots%20(aka%20SMO)%20navigate%20your%20website%20only%20by%20using%20HTML%20requests">crawl your website using HTML</Link>.


## Cumulative

The `+Head` setting is cumulative. For example:

```jsx
// /pages/+Head.js
// Environment: server

import favicon from './favicon.png'

export const Head = () =>
  // This favicon applies to all pages
  <link rel="icon" href={favicon}>
```

```jsx
// /pages/about-us/+Head.js
// Environment: server

import previewImage from './previewImage.jpg'

export const Head = () =>
  // Both the favicon above and this tag applies to /pages/about-us/+Page.js
  <meta property="og:image" content={previewImage}>
```

To apply different `+Head` settings to different pages:

```jsx
// /pages/(marketing)/+Head.js
// Environment: server

import favicon from './favicon.png'

// Applies to all marketing pages
export const Head = () => <link rel="icon" href={favicon}>
```

```jsx
// /pages/admin/+Head.js
// Environment: server

import favicon from './favicon.png'

// Applies to all admin pages
export const Head = () => <link rel="icon" href={favicon}>
```

> See: <Link href="/config#inheritance"/>


> If you have a need for overriding, then add a comment at: [#1692 - Add `override` and `default` options for cumulative configs](https://github.com/vikejs/vike/issues/1692)


## How to inject raw HTML?

You can inject any arbitrary HTML string to the page's `<head>`. Examples using:

- <Link href="#react">React</Link>
- <Link href="#vue">Vue</Link>
- <Link href="#solid">Solid</Link>

<Warning>
Be cautious about the security risk called [XSS injections](https://en.wikipedia.org/wiki/Cross-site_scripting).
</Warning>

### React

You can use React's `dangerouslySetInnerHTML` to add raw HTML, for example:

```ts
import React from 'react'
import { Head } from 'vike-react/Head'

function Image({ src, author }) {
  return (
    <>
      <img src={src} />
      <Head>
        <script
          type="application/ld+json"
          dangerouslySetInnerHTML={{
            __html: JSON.stringify({
              '@context': 'https://schema.org/',
              contentUrl: { src },
              creator: {
                '@type': 'Person',
                name: author
              }
            })
          }}
        ></script>
      </Head>
    </>
  )
}
```

### Vue

You can use `innerHTML` to add raw HTML, for example:

```vue
<template>
  <img :src v-bind="otherAttrs" />
</template>

<script setup>
import { useAttrs, h } from 'vue'
import { useConfig } from 'vike-vue/useConfig'

const { src, author, ...otherAttrs } = useAttrs()

const config = useConfig()
config({
  Head: h('script', {
    type: 'application/ld+json',
    innerHTML: JSON.stringify({
      '@context': 'https://schema.org/',
      contentUrl: { src },
      creator: {
        '@type': 'Person',
        name: author
      }
    })
  })
})
</script>
```

### Solid

You can use `innerHTML` to add raw HTML, for example:

```jsx
import { Head } from "vike-solid/Head"

function Image({ src, author }) {
  return (
    <>
      <img src={src} />
      <Head>
        <script
          type="application/ld+json"
          innerHTML={JSON.stringify({
            "@context": "https://schema.org/",
            contentUrl: { src },
            creator: {
              "@type": "Person",
              name: author
            }
          })}
        ></script>
      </Head>
    </>
  )
}
```


## See also

- <Link href="/head-tags" />
- <Link href="/settings#html" doNotInferSectionTitle />
